#include "messager.h"
#include "ams.h"

// ##
#define LOG_TAG     "ams"
#include "log.h"

// ##
static ams_node_t *ams_root = NULL;

// ##
static ams_node_t *current = NULL;

// ##
static ams_activity_t *ams_current = NULL;

// ##
static volatile mMessager_t message_activity_id = NULL;

// ##
static ams_node_t *ams_create_item(void)
{
    ams_node_t *node = NULL;
    node = ams_malloc(sizeof(ams_node_t));
    ams_assert(node);

    node->item = ams_malloc(sizeof(ams_activity_t));
    ams_assert(node->item);

    node->next = NULL;

    return node;
}

void ams_activity_register(const ams_activity_t *item)
{
    ams_node_t *node = ams_create_item();
    if(!current)
    {
        ams_root = node;
    }
    else
    {
        current->next = node;
    }

    memcpy(node->item, item, sizeof(ams_activity_t));
    current = node;
}

/**
 * @description:
 * @param {ams_node_t} *ams_root
 * @param {ams_profile_node_t} *
 * @return {*}
 */
static void ams_copy_profile_node_list(ams_node_t *ams_root, ams_profile_node_t **list)
{
    // 创建一个指针p指向ams_root链表头部节点
    ams_node_t *p = ams_root;

    // 创建一个指针q指向list链表头部节点
    ams_profile_node_t *q = *list;

    // 遍历ams_root链表
    while (p != NULL)
    {
        uint32_t attr = p->item->attr;
        attr &= ACTIVITY_ATTR_FLAG_HOME | ACTIVITY_ATTR_FLAG_LIST;
        if (!(attr & (ACTIVITY_ATTR_FLAG_HOME | ACTIVITY_ATTR_FLAG_LIST)))
        {
            // 为新的ams_profile_node_t节点分配内存
            ams_profile_node_t *new_node = (ams_profile_node_t*)malloc(sizeof(ams_profile_node_t));

            // 将ams_node_t节点中的数据复制到新节点中
            new_node->icon = p->item->icon;
            new_node->name = p->item->name;
            new_node->next = NULL;

            // 如果链表头为空，则将链表头指向新节点
            if (*list == NULL)
            {
                *list = new_node;
                q = *list;
            }
            // 否则将新节点链接到链表尾部
            else
            {
                q->next = new_node;
                q = q->next;
            }
        }

        // 将指针p指向下一个节点
        p = p->next;
    }
}

/**
 * @description:
 * @param {ams_profile_node_t} *
 * @return {*}
 */
void ams_activity_get_list(ams_profile_node_t **list)
{
    ams_copy_profile_node_list(ams_root, list);
}

// ##
static void ams_gesture_event_handler(struct _lv_obj_t * obj, lv_event_t event)
{
    if(event != LV_EVENT_GESTURE)
        return;

    ams_gesture_t ams_gesture = lv_indev_get_gesture_dir(lv_indev_get_act());
    ams_current->ops->gesture(&ams_gesture);
}

// ##
void ams_event_listener_register(const msg_t msg)
{
    if(messager_bind(msg, message_activity_id) != RESULT_OK)
    {
        log_info("failed to bind msg : %d", msg);
    }
}

// ##
void ams_event_listener_unregister(const msg_t msg)
{
    if(messager_unbind(msg, message_activity_id) != RESULT_OK)
    {
        log_info("failed to unbind msg : %d", msg);
    }
}

// ##
void ams_init(const mMessager_t messager)
{
    ams_root = ams_create_item();
    ams_current = NULL;
    message_activity_id = messager;
}

// ##
void ams_event_handle(ams_event_t *event)
{
    ams_current->ops->handler(event);
}

// ##
ams_activity_t *ams_search_by_name(char *name)
{
    ams_node_t *mm = ams_root;
    while(mm != NULL)
    {
        ams_activity_t *item = mm->item;
        if(!strcmp(item->name, name))
        {
            return item;
        }
        else
        {
            mm = mm->next;
        }
    }

    return NULL;
}

// ##
void ams_switch_by_name(char *name, ams_dir_t dir)
{
    ams_activity_t *next = ams_search_by_name(name);
    if(!next)
    {
        log_error("app %s not found\r\n", name);
        return;
    }

    ams_activity_start(next, dir);
}

// ##
void *ams_activity_start(ams_activity_t *next, ams_dir_t dir)
{
    if(!next)
        return NULL;

    const lv_scr_load_anim_t anim_map[] =
    {
        LV_SCR_LOAD_ANIM_NONE,
        LV_SCR_LOAD_ANIM_MOVE_TOP,
        LV_SCR_LOAD_ANIM_MOVE_BOTTOM,
        LV_SCR_LOAD_ANIM_MOVE_LEFT,
        LV_SCR_LOAD_ANIM_MOVE_RIGHT,
        LV_SCR_LOAD_ANIM_OVER_TOP,
        LV_SCR_LOAD_ANIM_OVER_BOTTOM,
        LV_SCR_LOAD_ANIM_OVER_LEFT,
        LV_SCR_LOAD_ANIM_OVER_RIGHT,
    };

    const char *dir_name[] =
    {
        "dir_slide_to_none",
        "dir_slide_to_top",
        "dir_slide_to_bottom",
        "dir_slide_to_left",
        "dir_slide_to_right",
        "dir_cover_to_top",
        "dir_cover_to_bottom",
        "dir_cover_to_left",
        "dir_cover_to_right",
    };

    ams_activity_t *cur = (ams_activity_t *)ams_current;
    ams_current = next;
    next->ops->prepare(next);
    next->ui = next->ops->create(next);
    next->ops->start(next);
    lv_obj_set_event_cb(next->ui, ams_gesture_event_handler);
    lv_scr_load_anim(next->ui, anim_map[dir], 200, 100, false);
    log_info("switched to %s, %s\r\n", next->name, dir_name[dir]);

    if(!cur)
    {
        return next;
    }

    cur->ops->stop(cur);
    cur->ops->destroy(cur);

    return next;
}
